<template>
  <div />
</template>
<script>
import { useMessageBox } from "@/hooks/message";
import { useUserStore } from "@/store/modules/user";
import { toLoginRoute } from "@/utils/routes";
const { VITE_API_URL } = import.meta.env;
let apiBaseUrl = VITE_API_URL;

export default defineComponent({
  name: "GlobalWebsocket",
  components: {},
  props: {
    uri: {
      type: String,
      default: "/websocket"
    }
  },
  setup(props) {
    const { resetAll } = useUserStore();

    const router = useRouter();

    const state = reactive({
      webSocket: ref(), // webSocket实例
      lockReconnect: false, // 重连锁，避免多次重连
      maxReconnect: 6, // 最大重连次数， -1 标识无限重连
      reconnectTime: 0, // 重连尝试次数
      heartbeat: {
        interval: 30 * 1000, // 心跳间隔时间
        timeout: 10 * 1000 // 响应超时时间
      },
      token: null
    });

    onUnmounted(() => {
      state.webSocket.onclose();
    });

    const initWebSocket = token => {
      // ws地址
      const url = apiBaseUrl.replaceAll("http", "ws");
      state.token = token;
      const wsUri = `${url}${props.uri}/${token}`;
      // 建立连接
      state.webSocket = new WebSocket(wsUri);
      // 连接成功
      state.webSocket.onopen = onOpen;
      // 连接错误
      state.webSocket.onerror = onError;
      // 接收信息
      state.webSocket.onmessage = onMessage;
      // 连接关闭
      state.webSocket.onclose = onClose;
    };

    const reconnect = () => {
      if (!state.token) {
        return;
      }
      if (
        state.lockReconnect ||
        (state.maxReconnect !== -1 && state.reconnectTime > state.maxReconnect)
      ) {
        return;
      }
      state.lockReconnect = true;
      setTimeout(() => {
        state.reconnectTime++;
        // 建立新连接
        initWebSocket(state.token);
        state.lockReconnect = false;
      }, 5000);
    };

    /**
     * 连接成功事件
     */
    const onOpen = () => {
      state.reconnectTime = 0;
    };
    /**
     * 连接失败事件
     * @param e
     */
    const onError = () => {
      //重连
      reconnect();
    };

    /**
     * 连接关闭事件
     * @param e
     */
    const onClose = () => {
      state.webSocket.close();
    };

    /**
     * 接收服务器推送的信息
     * @param msgEvent
     */
    const onMessage = msgEvent => {
      const message = msgEvent.data;
      if (message === "opened") return;
      let confirmTitle = "当前登录用户已在其他设备登录,请重新登录！";
      if (message === "replaced") {
        confirmTitle = "当前登录用户已在其他设备登录,请重新登录！";
      } else if (message === "kickout") {
        confirmTitle = "当前登录会话已被踢下线,请重新登录！";
      } else if (message === "disable") {
        confirmTitle = "当前登录用户已被封禁,请重新登录！";
      }
      useMessageBox()
        .confirm(confirmTitle)
        .then(async () => {
          const loginPath = toLoginRoute("/");
          await resetAll();
          await router.push(loginPath);
        })
        .catch(async () => {
          const loginPath = toLoginRoute("/");
          await resetAll();
          await router.push(loginPath);
        });
    };

    return {
      ...toRefs(state),
      initWebSocket,
      reconnect,
      onOpen,
      onError,
      onClose,
      onMessage
    };
  }
});
</script>
